#include "fxcc/core/graph/opengl3/ImGuiGlfwApp.h"
#include "fxcc/core/graph/common/Geometry.h"
#include "fxcc/core/graph/common/BoneNode.h"

#include "fxcc/core/graph/common/Scene.h"
#include "fxcc/core/graph/opengl3/Resources.h"
#include "fxcc/imgui/Editor.h"

using namespace fxcc::platform;
using namespace fxcc::graph;
using namespace fxcc::graph::opengl3;
using namespace fxcc::imgui::graph::opengl3;
using BaseApp = fxcc::imgui::graph::opengl3::GlfwApp;

#undef main

struct SimpleApp : public BaseApp
{
public:
    fxcc::graph::common::Transform transform;

    std::shared_ptr<fxcc::graph::opengl3::RenderTargetJack> m_RenderTarget;

    std::shared_ptr<fxcc::graph::opengl3::MeshJack> m_CubeMesh;
    
    std::shared_ptr<fxcc::graph::opengl3::Texture2DJack> m_Texture2DJack;

    glm::vec4 color;

    std::shared_ptr<fxcc::graph::opengl3::Effect3d> m_Effect;

    std::shared_ptr<fxcc::graph::common::BoneNode> m_BoneNode;

    fxcc::graph::common::Camera camera;

    SimpleApp(const fxcc::platform::common::App::Desc &desc) : BaseApp(desc), color(1.0)
    {
    }
    bool Init() override
    {
        if (!BaseApp::Init())
        {
            return false;
        }

        if (!InitResources())
        {
            return false;
        }

        return true;
    };

    fxcc::graph::common::Effect3d::BoneData m_BoneData;

    void printOpenGLESVersion()
    {
        const char *version = (const char *)glGetString(GL_VERSION);
        std::cout << "OpenGL ES Version: " << version << std::endl;
    };

    bool InitResources()
    {
        transform.m_Scale = glm::vec3(1.f);

        camera.SetPosition(glm::vec3(50.0f));
        camera.LookAt(glm::vec3(0.0f));
        camera.nNear = 1.0f;
        //camera.nFar= 2500.0f;
        const std::string fragCode = R"(

layout (location=0) out vec4 FragColor0;
layout (location=1) out vec4 FragColor1;
layout (location=2) out vec4 FragColor2;

uniform sampler2D diffuse;

void main()
{
	FragColor0=texture(diffuse,TexCoord);
    FragColor1=vec4(vec3(0.5f,1.0f,0.5f),1.0f);
    FragColor2=vec4(vec3(1.f,1.0f,0.5f),1.0f);
}
)";
        m_Effect = std::make_shared<fxcc::graph::opengl3::Effect3d>(fragCode);
        m_CubeMesh = std::make_shared<fxcc::graph::opengl3::MeshJack>(fxcc::graph::common::Geometry::CreateBox());

        auto& am = fxcc::AssertManager::Inst();
        {
            fxcc::graph::common::Texture2DJack::Desc desc;
            desc.SetDDS(am.GetFile("Model/Sponza/sponza_fabric_blue_diff.dds"));
            desc.SetWIC(am.GetFile("container.jpg"));
            m_Texture2DJack = std::make_shared<fxcc::graph::opengl3::Texture2DJack>(desc);

        }
        {

            std::string scenePath = am.GetFile("Model/powerplant/powerplant.gltf");

            auto& commonRS = fxcc::graph::common::Resources::Inst();
            auto& graphRS = fxcc::graph::opengl3::Resources::Inst();

            if (!graphRS.LoadScene(scenePath))
            {
                ztclog::info("failed load graph rs");
                return false;
            }

            if (commonRS.HasScene(scenePath))
            {
                auto scene = commonRS.GetScene(scenePath);
                m_BoneNode = std::make_shared<fxcc::graph::common::BoneNode>(scene.get());
            }

        }

        return true;
    };

    fxcc::imgui::Editor editor;
    ;

    void OnEdit() override
    {
        ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());

        ImGui::Begin("RT");
        editor.EditInst<fxcc::graph::common::RenderTargetJack>("rt", *m_RenderTarget);
        ImGui::End();

        ImGui::Begin("texture");
        editor.EditInst<fxcc::graph::common::Texture2DJack>("diffuse", *m_Texture2DJack);
        ImGui::End();

        ImGui::Begin("attachment0");
        editor.AddFrameBuffer(m_RenderTarget->m_Textures[0]->GetTextureId());
        ImGui::End();

        ImGui::Begin("commonResources");

        for (auto [key, value] : fxcc::graph::common::Resources::Inst().m_Materials)
        {
            editor.EditInst<fxcc::graph::common::MaterialData>(value->m_Name, *value);
        }
        ImGui::End();

        ImGui::Begin("opengl Resources");

        ImGui::End();
    }
    void OnDestroy() override
    {
      
        BaseApp::OnDestroy();
    }
    void OnFrameRender() override
    {
        glViewport(0, 0, m_Desc.m_Size.x, m_Desc.m_Size.y);

        glClearColor(color.x, color.y, color.z, color.w);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        m_RenderTarget->Begin();

        m_Effect->Begin();
        m_Effect->SetCamera(camera);
        m_Effect->m_Shader->Use();
        m_Effect->m_Shader->setInt("diffuse", 0);

        auto& graphRS = fxcc::graph::opengl3::Resources::Inst();
        auto& commonRS = fxcc::graph::common::Resources::Inst();

        for (auto [key, value] :graphRS.m_FixedMeshes)
        {
            auto matDataIndex = key;
            matDataIndex.m_Index = commonRS.m_MeshDatas[key]->m_MaterialIndex;

            graphRS.m_GraphMaterials[matDataIndex]->Use();

            m_Effect->InstMeshJack(value.get(), transform);
            //m_Effect->InstSkinnedMeshJack(value.get(), transform, m_BoneData);

        }
        //m_Effect->InstMeshJack(m_CubeMesh.get(), transform);
        m_Effect->End();

        m_RenderTarget->End();
    };

    void OnFramebuffersize(int w, int h) override
    {
        opengl3::GlfwApp::OnFramebuffersize(w, h);
        camera.SetAspect(m_Desc.Aspect());
        
        const int numAttachment = 1;
        fxcc::graph::common::RenderTargetJack::Desc desc(numAttachment, w, h, 4, 0);
        m_RenderTarget = std::make_shared<fxcc::graph::opengl3::RenderTargetJack>(desc);

    }
    void OnUpdate() override
    {
        opengl3::GlfwApp::OnUpdate();

        float ctTime = m_GlfwlTimer.m_CurrentTime;
        camera.FreeMove(m_Input, m_GlfwlTimer.m_DeltaTime, { 50.0f,50.0f });

        float deltaTime = m_GlfwlTimer.m_DeltaTime;

        m_BoneNode->ProcessNode(fxcc::graph::common::Transform());
        m_BoneNode->UpdateBuffer(m_BoneData);
    }
};

int main()
{
    ztclog::pushFunction([](const ztclog::Line &line)
                         {
		if (line.m_Type != ztclog::Line::Type::_line_debug_)
		{
			std::cout << line.m_Text << std::endl;
		} });

    using _App = SimpleApp;
    using _Desc = fxcc::platform::common::App::Desc;

    _Desc desc;
    desc.m_Pos = glm::ivec2(100, 100);
    desc.m_Size = glm::ivec2(900, 600);
    desc.m_ScaleFactor = 1.0f;

    desc.m_Title = "test font";
    std::shared_ptr<_App> _app = std::make_shared<_App>(desc);
    return _app->Run();
};
